﻿namespace UnityEditor
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Text.RegularExpressions;

    internal class PRXTools
    {
        private static string scePath = Environment.GetEnvironmentVariable("SCE_PS3_ROOT");

        internal static void ConvertToStrippedSPRX(bool needsDrm, string filePath, string targetCrossCompiledASMFolder)
        {
            string str = Path.GetDirectoryName(filePath) + "/" + Path.GetFileNameWithoutExtension(filePath);
            string outputFile = str + ".prx";
            string processFileName = Path.Combine(scePath, "host-win32/bin/unfself.exe");
            string[] textArray1 = new string[] { " \"", filePath, "\" \"", outputFile, "\"" };
            string inputArguments = string.Concat(textArray1);
            ExternalTool.StartProcess(processFileName, inputArguments, outputFile, true, string.Empty);
            filePath = outputFile;
            string str5 = Path.Combine(scePath, "host-win32/bin/ppu-lv2-prx-strip");
            string str6 = " \"" + filePath + "\"";
            ExternalTool.StartProcess(str5, str6, filePath, true, string.Empty);
            string str7 = str + ".sprx";
            string str8 = Path.Combine(scePath, !needsDrm ? "host-win32/bin/make_fself" : "host-win32/bin/make_fself_npdrm");
            string[] textArray2 = new string[] { " \"", filePath, "\" \"", str7, "\" " };
            string str9 = string.Concat(textArray2);
            ExternalTool.StartProcess(str8, str9, str7, true, string.Empty);
            File.Delete(filePath);
        }

        internal static void CreateBootstrapPRX(string targetCrossCompiledASMFolder, string sourceAssembliesFolder, string playerPackage, string bootstrapFile, PRXModuleInfo moduleInfo)
        {
            string str = "B_" + moduleInfo.name;
            string str2 = Path.Combine(targetCrossCompiledASMFolder, str);
            string path = str2 + ".cpp";
            string outputFile = str2 + ".o";
            string str5 = str2 + ".prx";
            string str6 = str2 + ".map";
            StreamWriter writer = new StreamWriter(path);
            writer.WriteLine("#include <stdio.h>");
            writer.WriteLine("#include <stdlib.h>");
            writer.WriteLine("#include <string.h>");
            writer.WriteLine("#include <sdk_version.h>");
            writer.WriteLine("#include <cellstatus.h>");
            writer.WriteLine("#include <sys/prx.h>");
            writer.WriteLine(string.Empty);
            writer.WriteLine("SYS_MODULE_INFO(" + ReduceName(str) + ", 0, 1, 1); ");
            writer.WriteLine("SYS_MODULE_START(Register_" + moduleInfo.name + ");");
            writer.WriteLine(string.Empty);
            foreach (string str7 in moduleInfo.exports)
            {
                writer.WriteLine("extern \"C\"  int " + str7 + "();");
            }
            writer.WriteLine(string.Empty);
            writer.WriteLine("typedef int (*EXTERNFUNCTION)();");
            writer.WriteLine("static struct FunctionMap { const char* name; EXTERNFUNCTION address;} s_FunctionNames [] =  {");
            writer.WriteLine(string.Empty);
            foreach (string str8 in moduleInfo.exports)
            {
                writer.WriteLine("  { \"" + str8 + "\", " + str8 + "},");
            }
            writer.WriteLine("};");
            writer.WriteLine(string.Empty);
            writer.WriteLine("extern \"C\" void RegisterModule(const char* module_name, void* exports, size_t exports_count);");
            writer.WriteLine(string.Empty);
            writer.WriteLine("extern \"C\" int Register_" + moduleInfo.name + "(unsigned int args, void* argp) {");
            writer.WriteLine("  RegisterModule(\"" + ReduceName(moduleInfo.name) + "\", s_FunctionNames, sizeof(s_FunctionNames)/sizeof(s_FunctionNames[0]));");
            writer.WriteLine("  return SYS_PRX_RESIDENT;");
            writer.WriteLine("}");
            writer.Close();
            string processFileName = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-gcc");
            string inputArguments = " -Wall -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections ";
            string str17 = inputArguments;
            string[] textArray2 = new string[] { str17, " -c \"", path, "\" -o \"", outputFile, "\"" };
            inputArguments = string.Concat(textArray2);
            ExternalTool.StartProcess(processFileName, inputArguments, outputFile, true, string.Empty);
            File.Delete(path);
            string str11 = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-gcc");
            str17 = ((" -fno-exceptions -fno-rtti -mprx -zgenprx -zgc-sections -lc_stub -lm_stub -lstdc++_stub -Wl,-Map=\"" + str6 + "\"") + " \"" + moduleInfo.stub + "\" ") + " \"" + Path.Combine(playerPackage, "Tools/PRX/PRXManager_stub.a") + "\" ";
            string[] textArray3 = new string[] { str17, "\"", outputFile, "\" -o \"", str5, "\"" };
            string str12 = string.Concat(textArray3);
            ExternalTool.StartProcess(str11, str12, str5, true, string.Empty);
            File.Delete(outputFile);
            string str13 = Path.Combine(scePath, "host-win32/bin/ppu-lv2-prx-strip");
            string str14 = " \"" + str5 + "\"";
            ExternalTool.StartProcess(str13, str14, str5, true, targetCrossCompiledASMFolder);
            bool flag = PS3BuildSubtarget.HddTitle == EditorUserBuildSettings.ps3BuildSubtarget;
            string str15 = Path.Combine(scePath, !flag ? "host-win32/bin/make_fself" : "host-win32/bin/make_fself_npdrm");
            string[] textArray4 = new string[] { " \"", str5, "\" \"", bootstrapFile, "\" " };
            string str16 = string.Concat(textArray4);
            ExternalTool.StartProcess(str15, str16, bootstrapFile, true, string.Empty);
            File.Delete(str5);
        }

        internal static string CreateExportsFile(string targetDir, PRXModuleInfo moduleInfo)
        {
            string path = Path.Combine(targetDir, moduleInfo.name + "exports.c");
            StreamWriter writer = new StreamWriter(path);
            writer.WriteLine("#include <stdio.h>");
            writer.WriteLine("#include <stdlib.h>");
            writer.WriteLine("#include <string.h>");
            writer.WriteLine("#include <sdk_version.h>");
            writer.WriteLine("#include <cellstatus.h>");
            writer.WriteLine("#include <sys/prx.h>");
            writer.WriteLine(string.Empty);
            writer.WriteLine("SYS_MODULE_INFO(" + ReduceName(moduleInfo.name) + ", 0, 1, 1); ");
            writer.WriteLine("SYS_LIB_DECLARE(" + moduleInfo.name + ", SYS_LIB_AUTO_EXPORT);");
            writer.WriteLine(string.Empty);
            foreach (string str2 in moduleInfo.exports)
            {
                writer.WriteLine("SYS_LIB_EXPORT(" + str2 + ", " + moduleInfo.name + ");");
            }
            writer.WriteLine(string.Empty);
            writer.Close();
            return path;
        }

        internal static void CreateMainLibrary(PS3BuildSubtarget ps3Subtarget, bool installInBuildsFolder, string titleID, string kLicenseeString, string stagingAreaData, string playerPackage)
        {
            string str = stagingAreaData + "/AOTCompileStep";
            str = Path.Combine(Directory.GetCurrentDirectory(), str);
            string destFileName = Path.Combine(stagingAreaData, "PRXManager.sprx");
            File.Copy(Path.Combine(playerPackage, "Tools/PRX/PRXManager.sprx"), destFileName);
            int num = PlayerSettings.ps3BootCheckMaxSaveGameSizeKB;
            string str12 = ("#include <sys/types.h>\n" + "#include <np/drm.h>\n") + "const SceNpDrmKey g_PS3TitleLicenseeKey = { " + kLicenseeString + " };\n";
            object[] objArray1 = new object[] { str12, "const int g_PS3TitleMaxSaveGameKB = ", num, ";\n" };
            str12 = string.Concat(objArray1);
            object[] objArray2 = new object[] { str12, "const int g_PS3TitleTrialMode = ", !PlayerSettings.ps3TrialMode ? 0 : 1, ";\n" };
            str12 = string.Concat(objArray2);
            string contents = ((((((((((string.Concat(new object[] { str12, "const int g_PS3SaveGameSlots = ", PlayerSettings.ps3SaveGameSlots, ";\n" }) + "const char * g_PS3TitleTrophyCommId = \"" + PlayerSettings.ps3TrophyCommId + "\";\n") + "const char g_PS3TitleTrophyCommSig[] = { " + PlayerSettings.ps3TrophyCommSig + " };\n") + "const int g_PS3TitleTrophyCommSigLength = sizeof(g_PS3TitleTrophyCommSig) / sizeof(g_PS3TitleTrophyCommSig[0]);\n") + "const char* g_PS3TitleID = \"" + titleID + "\";\n") + "\n") + "\nconst char* GetBasePath() {\n" + "\t#if defined(HDD)\n") + "\t\treturn \"/dev_hdd0/game/" + titleID + "/USRDIR/\";\n") + "\t#elif defined(BLURAY)\n" + "\t\treturn \"/dev_bdvd/PS3_GAME/USRDIR/\";\n") + "\t#elif defined(PCHOSTED)\n" + "\t\treturn \"/app_home/PS3_GAME/USRDIR/\";\n") + "\t#else\n" + "\t\treturn \"/app_home/\";\n") + "\t#endif\n" + "}\n\n";
            string outputFile = Path.Combine(str, "FileAccessModule.o");
            EditorUtility.DisplayProgressBar("Building Player", "Setting up file access module", 0.95f);
            string path = Path.Combine(str, "FileAccessModule.c");
            File.WriteAllText(path, contents);
            string processFileName = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-gcc.exe");
            string[] textArray1 = new string[] { " -c \"", path, "\" -O3 -o \"", outputFile, "\"" };
            string inputArguments = string.Concat(textArray1);
            if (ps3Subtarget == PS3BuildSubtarget.HddTitle)
            {
                inputArguments = inputArguments + " -DHDD";
            }
            else if (ps3Subtarget == PS3BuildSubtarget.BluRayTitle)
            {
                inputArguments = inputArguments + " -DBLURAY";
            }
            else if ((ps3Subtarget == PS3BuildSubtarget.PCHosted) && !installInBuildsFolder)
            {
                inputArguments = inputArguments + " -DPCHOSTED";
            }
            ExternalTool.StartProcess(processFileName, inputArguments, outputFile, true, string.Empty);
            string str8 = Path.Combine(stagingAreaData, "MonoAssembliesPS3.a");
            string str9 = Path.Combine(str, "snarl.mri");
            StreamWriter writer = new StreamWriter(str9);
            writer.WriteLine("Create \"" + str8 + "\"");
            writer.WriteLine("addmod \"" + outputFile + "\"");
            writer.WriteLine("addlib \"" + Path.Combine(playerPackage, "Tools/PRX/PRXManager_stub.a") + "\"");
            writer.WriteLine("Save");
            writer.WriteLine("End");
            writer.Close();
            string str10 = Path.Combine(scePath, "host-win32/sn/bin/ps3snarl.exe");
            string str11 = " -M \"" + str9 + "\" ";
            ExternalTool.StartProcess(str10, str11, str8, true, string.Empty);
            File.Delete(str9);
        }

        internal static string CreateMonoAssemblyPRX(string targetCrossCompiledASMFolder, string sourceFile, string sourceAssembliesFolder, string playerPackage)
        {
            string filePath = Path.Combine(targetCrossCompiledASMFolder, Path.GetFileName(sourceFile));
            string str2 = Path.Combine(sourceAssembliesFolder, Path.GetFileName(sourceFile));
            string str3 = filePath + ".s";
            string outputFile = filePath + ".o";
            string processFileName = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-as.exe");
            string[] textArray1 = new string[] { "\"", str3, "\" -o \"", outputFile, "\"" };
            string inputArguments = string.Concat(textArray1);
            ExternalTool.StartProcess(processFileName, inputArguments, outputFile, true, string.Empty);
            PRXModuleInfo moduleInfo = ExtractModuleInfoFromOBJ(filePath);
            string str7 = CreateExportsFile(targetCrossCompiledASMFolder, moduleInfo);
            string str8 = filePath + ".prx";
            string str9 = str2 + ".map";
            string str10 = str2 + ".sprx";
            string bootstrapFile = str2 + ".sprx.b.sprx";
            string str12 = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-gcc.exe");
            string[] textArray2 = new string[] { " \"", outputFile, "\" \"", str7, "\" -mprx -zgenstub  -Wl,-Map=\"", str9, "\" -o \"", str8, "\"" };
            string str13 = string.Concat(textArray2);
            ExternalTool.StartProcess(str12, str13, str8, true, targetCrossCompiledASMFolder);
            string str14 = Path.Combine(scePath, "host-win32/bin/ppu-lv2-prx-strip");
            string str15 = " \"" + str8 + "\"";
            ExternalTool.StartProcess(str14, str15, str8, true, targetCrossCompiledASMFolder);
            bool flag = PS3BuildSubtarget.HddTitle == EditorUserBuildSettings.ps3BuildSubtarget;
            string str16 = Path.Combine(scePath, !flag ? "host-win32/bin/make_fself" : "host-win32/bin/make_fself_npdrm");
            string[] textArray3 = new string[] { " \"", str8, "\" \"", str10, "\"" };
            string str17 = string.Concat(textArray3);
            ExternalTool.StartProcess(str16, str17, str10, true, string.Empty);
            CreateBootstrapPRX(targetCrossCompiledASMFolder, sourceAssembliesFolder, playerPackage, bootstrapFile, moduleInfo);
            return str10;
        }

        internal static bool CreateNativePluginsPRX(bool needsDrm, string targetCrossCompiledASMFolder, string playerPackage, string pluginFolder)
        {
            targetCrossCompiledASMFolder = Path.Combine(Directory.GetCurrentDirectory(), targetCrossCompiledASMFolder);
            string strB = ".sprx";
            foreach (string str2 in Directory.GetFileSystemEntries(pluginFolder))
            {
                if ((string.Compare(Path.GetExtension(str2), strB, true) == 0) || (string.Compare(Path.GetFileName(str2), strB, true) == 0))
                {
                    string filePath = Path.GetDirectoryName(str2) + "/" + Path.GetFileName(str2);
                    PRXModuleInfo moduleInfo = ExtractGlobalSymbolsFromPRX(filePath);
                    string bootstrapFile = Path.Combine(pluginFolder, Path.GetFileName(str2) + ".b.sprx");
                    CreateBootstrapPRX(targetCrossCompiledASMFolder, pluginFolder, playerPackage, bootstrapFile, moduleInfo);
                    ConvertToStrippedSPRX(needsDrm, filePath, targetCrossCompiledASMFolder);
                }
            }
            return true;
        }

        internal static PRXModuleInfo ExtractGlobalSymbolsFromPRX(string filePath)
        {
            PRXModuleInfo info;
            info = new PRXModuleInfo {
                name = Path.GetFileNameWithoutExtension(filePath),
                name = info.name.Replace(".", "_"),
                name = info.name.Replace("-", "_"),
                name = info.name.Replace(" ", "_")
            };
            string str = Path.GetDirectoryName(filePath) + "/" + Path.GetFileNameWithoutExtension(filePath);
            string outputFile = str + ".prx";
            info.stub = str + "_stub.a";
            string processFileName = Path.Combine(scePath, "host-win32/bin/unfself.exe");
            string[] textArray1 = new string[] { " \"", filePath, "\" \"", outputFile, "\"" };
            string inputArguments = string.Concat(textArray1);
            ExternalTool.StartProcess(processFileName, inputArguments, outputFile, true, string.Empty);
            string path = filePath + ".globals";
            string str6 = Path.Combine(scePath, "host-win32/bin/ppu-lv2-prx-info.exe");
            string str7 = " --show-global-symbols \"" + outputFile + "\"";
            Process process = new Process {
                StartInfo = { FileName = "cmd.exe" }
            };
            string[] textArray2 = new string[] { " /C ", str6, str7, " > \"", path, "\" " };
            process.StartInfo.Arguments = string.Concat(textArray2);
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.RedirectStandardError = true;
            process.Start();
            process.WaitForExit();
            if ((process.ExitCode != 0) || !File.Exists(path))
            {
                throw new System.Exception(process.StartInfo.FileName + process.StartInfo.Arguments + " : " + process.StandardError.ReadToEnd());
            }
            StreamReader reader = new StreamReader(path);
            while (!reader.EndOfStream)
            {
                Match match = Regex.Match(reader.ReadLine(), @"EGN \((\w+)\)((\w+))", RegexOptions.IgnoreCase);
                if (match.Success)
                {
                    if (match.Groups[1].Value != info.name)
                    {
                        string[] textArray3 = new string[] { "Module name must match the file name of the SPRX ( ", info.name, " != ", match.Groups[1].Value, " ). Bailing out" };
                        throw new System.Exception(string.Concat(textArray3));
                    }
                    info.exports.Add(match.Groups[2].Value);
                }
            }
            reader.Close();
            File.Delete(path);
            File.Delete(outputFile);
            return info;
        }

        internal static PRXModuleInfo ExtractModuleInfoFromOBJ(string filePath)
        {
            PRXModuleInfo info;
            info = new PRXModuleInfo {
                name = Path.GetFileName(filePath),
                name = info.name.Replace(".", "_"),
                name = info.name.Replace("-", "_"),
                name = info.name.Replace(" ", "_"),
                stub = Path.Combine(Path.GetDirectoryName(filePath), info.name + "_stub.a")
            };
            string path = filePath + ".symbols";
            string str2 = Path.Combine(scePath, "host-win32/ppu/bin/ppu-lv2-objdump.exe");
            string str3 = " -t \"" + filePath + ".o\" ";
            Process process = new Process {
                StartInfo = { FileName = "cmd.exe" }
            };
            string[] textArray1 = new string[] { " /C ", str2, str3, " > \"", path, "\" " };
            process.StartInfo.Arguments = string.Concat(textArray1);
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.RedirectStandardError = true;
            process.Start();
            process.WaitForExit();
            if ((process.ExitCode != 0) || !File.Exists(path))
            {
                throw new System.Exception(process.StartInfo.FileName + process.StartInfo.Arguments + " : " + process.StandardError.ReadToEnd());
            }
            StreamReader reader = new StreamReader(path);
            while (!reader.EndOfStream)
            {
                Match match = Regex.Match(reader.ReadLine(), @"(\w{16})(\s+)g(\s+)(\w)(\s+).(\w+)(\s+)(\w{16})(\s+)(\w+)", RegexOptions.IgnoreCase);
                if (match.Success)
                {
                    info.exports.Add(match.Groups[10].Value);
                }
            }
            reader.Close();
            File.Delete(path);
            return info;
        }

        internal static string ReduceName(string longName)
        {
            if (longName.Length < 0x1a)
            {
                return longName;
            }
            return longName.Substring(0, 0x1a);
        }
    }
}

